package edu.hubu.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.hubu.commons.RedisUtils;
import net.moon.commons.ResultsJson;
import net.moon.commons.StatusCode;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Set;

/**
 * 缓存注解切面，缓存所有、缓存一个、清除当前类所有缓存
 */
@Aspect
@Component
@EnableAspectJAutoProxy
public class CacheAop {

    ObjectMapper om=new ObjectMapper();

    @Autowired
    private RedisUtils redisUtils;

    //切入点为所有的findByLikePage方法
    @Pointcut("execution(* edu.hubu.service.impl.*.findByLikePage(..))")
    private void cacheOnePointCut(){};

    @Pointcut("@annotation(edu.hubu.aspect.ClassCacheEvict)")
    private void cacheEvictPointCut(){};
    @Pointcut("execution(* edu.hubu.service.impl.*.findAllPage(..))")
    private void cacheAllPointCut(){};
    /**
     * 模糊查询加该注解只缓存byId查询
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("cacheOnePointCut()")
    @Transactional
    public Object aroundFindLike(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        //获取id
        HashMap<String, Object> map = (HashMap<String, Object>) args[2];
        //获取代理对象类名
        String name=pjp.getTarget().getClass().getSimpleName();
        //实体类名，用于获取代理对象实体类的ID
        String modelName=name.substring(0, name.indexOf("Service")).toLowerCase();
        //存入redis的key前缀
        String prefix=name.substring(0, name.indexOf("Service"));
        String id = modelName+"Id";
        //userSid
        if (prefix.equalsIgnoreCase("user")){
            id = modelName+"Sid";
        }
        Object oid = map.get(id);
        //如果不是查询详情
        if (oid==null){
            return pjp.proceed(args);
        }
        String key=prefix+"::"+oid;
        Object one = redisUtils.get(key);
        //不在缓存
        if (one == null){
            ResultsJson resultsJson= (ResultsJson) pjp.proceed(args);
            //String序列化
            String s = om.writeValueAsString(resultsJson.getData());
            redisUtils.set(key,s);
            return resultsJson;
        }
        //查缓存
        Object o = new ObjectMapper().readValue(one.toString(), Object.class);
        return ResultsJson.toJson(StatusCode.SUCCESS,1,2,o);
    }

    /**
     * 缓存所有类的查询所有结果
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("cacheAllPointCut()")
    @Transactional
    public Object aroundFindAll(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        //获取代理对象类名
        String name=pjp.getTarget().getClass().getSimpleName();
        String prefix=name.substring(0, name.indexOf("Service"));

        String key=prefix+"::"+"all-"+args[0].toString()+"-"+args[1].toString();
        Object one = redisUtils.get(key);
        //不在缓存
        if (one == null){
            ResultsJson resultsJson= (ResultsJson) pjp.proceed(args);
            //String序列化
            String s = om.writeValueAsString(resultsJson.getData());
            redisUtils.set(key,s);
            return resultsJson;
        }
        //查缓存
        Object o = new ObjectMapper().readValue(one.toString(), Object.class);
        return ResultsJson.toJson(StatusCode.SUCCESS,1,2,o);
    }
    /**
     * 清除当前类的所有缓存
     * @param jp
     */
    @Before("cacheEvictPointCut()")
    public void beforeInvocation(JoinPoint jp){
        Class<?> clazz = jp.getTarget().getClass();
        String name = clazz.getSimpleName();
        String prefix = name.substring(0, name.indexOf("Service"));
        Set<String> keys = redisUtils.keys(prefix + "*");
        assert keys != null;
        if (!keys.isEmpty()){
            redisUtils.deletePrefix(prefix);
        }
    }
}

